using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using UnityEngine;

namespace Runtime.Common.Utility
{
    public class MethodReplaceUtil
    {
        public static bool ReplaceMethod(MethodInfo method, MethodInfo new_method)
        {
            if (IntPtr.Size != 8 || new_method.IsVirtual)
            {
                // 仅仅支持 x64
                // 替换用的函数必须是普通函数
                return false;
            }

            RuntimeHelpers.PrepareMethod(method.MethodHandle);
            RuntimeHelpers.PrepareMethod(new_method.MethodHandle);
            try
            {
                // 虚函数
                if (method.IsVirtual)
                {
                    return ReplaceVirtualMethod(method, new_method);
                }

                // 普通函数
#if DEBUG
                const bool buildModelDebug = true;
#else
                const bool buildModelDebug = false;
#endif
                if (buildModelDebug && Debugger.IsAttached)
                {
                    return ReplaceMethod_Debug_Attached(method, new_method);
                }
                else
                {
                    return ReplaceMethod_Release(method, new_method);
                }
            }
            catch (Exception e)
            {
                return false;
            }
        }

        // [1]普通成员函数
        static bool ReplaceMethod_Release(MethodInfo method, MethodInfo new_method)
        {
            unsafe
            {
                long* inj = (long*)new_method.MethodHandle.Value.ToPointer() + 1;
                long* tar = (long*)method.MethodHandle.Value.ToPointer() + 1;
                *tar = *inj;
            }

            return true;
        }

        // [2]普通成员函数(Debug且Attached处理)
        static bool ReplaceMethod_Debug_Attached(MethodInfo method, MethodInfo new_method)
        {
            unsafe
            {
                long* inj = (long*)new_method.MethodHandle.Value.ToPointer() + 1;
                long* tar = (long*)method.MethodHandle.Value.ToPointer() + 1;
                byte* injInst = (byte*)*inj;
                byte* tarInst = (byte*)*tar;

                int* injSrc = (int*)(injInst + 1);
                int* tarSrc = (int*)(tarInst + 1);

                *tarSrc = *injSrc + ((int)injInst - (int)tarInst);
            }

            return true;
        }

        // [3]处理虚函数
        // method 是虚函数
        // new_method 是普通函数
        static bool ReplaceVirtualMethod(MethodInfo method, MethodInfo new_method)
        {
            unsafe
            {
                UInt64* methodDesc = (UInt64*)(method.MethodHandle.Value.ToPointer());
                int index = (int)(((*methodDesc) >> 32) & 0xFF);

                ulong* classStart = (ulong*)method.DeclaringType.TypeHandle.Value.ToPointer();
                classStart += 8;
                classStart = (ulong*)*classStart;
                ulong* tar = classStart + index;
                ulong* inj = (ulong*)new_method.MethodHandle.Value.ToPointer() + 1;
                *tar = *inj;
            }

            return true;
        }
    }
}